/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __GDATA_SERIALIZER_H__
#define __GDATA_SERIALIZER_H__

#include "Object.h"

namespace PQEngine
{
	//simple data transfer protocal
	enum GDataType
	{
		GTYPE_BOOL,
		GTYPE_INT,
		GTYPE_FLOAT,
		GTYPE_DOUBLE,
		GTYPE_STRING,
		GTYPE_BYTES,//plain binary bytes

		//enum ObjectType  from engine
		GTYPE_OBJECT_TYPE,
		
		
	};

	enum GDataName
	{
		GDATA_UNKOWN,

		//COMMANDS
		GDATA_COMMAND_ADD_RESOURCE,
		GDATA_COMMAND_ADD_CHR_MODEL,
		GDATA_COMMAND_CREATE_OBJECT,

		GDATA_MESH_INFO,

		//scene serialize
		GDATA_GAMEOBJECT_TREE,
		GDATA_RESOURCE_LOCATION,
		GDATA_SCENE_CAMERA,
		GDATA_CHARACTER_MODEL,
	
		//framework use persist
		GDATA_PERSIST_ASSETS_ARCHIVE,
		

		GDATA_PERSIST_PROJECTS,//becareful with projects or project
		GDATA_PERSIST_PROJECT,

		GDATA_PERSIST_GPK_ASSIST,//.gpkassist

		GDATA_COMMAND_ADD_GPACK_RESOURCE,
		GDATA_COMMAND_CREATE_TERRAIN_OBJECT,
		//NOTE::Above sequence are fixed,New add just above here!!for we serialize data into disk.
	};
	
	class GDatagram
	{
	public:
		//header contains packet id(int) and packet body length(int)
		enum { HEADER_LENGTH = 8 };

		GDatagram(int count);
		GDatagram(char* data,int count);
		~GDatagram();
		int getId();
		char* data();
		int length();
		char* body();
		//decode header,get body length in bytes
		int getBodyLength();

		void write(int i);
		void write(float f);
		void write(char* buf,int count);

		bool readBool();
		int readInt();
		float readFloat();		
		double readDouble();
		std::string readString(int bytes);
		char* readBytes(int bytes);

	private:
		char* _data;
		int _pos;
		static int _count;//the count of datagrams produces
	};

	//parse srcp param
	class GDataParam
	{
	private:
		GDataType _type;//the param type (INT,UTF8_STR,_data,...)
		char* _data;//for _data,all should convert to this
		int _count;

	public:
		GDataParam(bool b);
		GDataParam(int i);	
		GDataParam(float f);
		GDataParam(double d);
		GDataParam(std::string str);
		GDataParam(ObjectType type);
		GDataParam(char* bytes,int count);
		~GDataParam();

		inline static bool isBoolParam(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_BOOL){
					return true;
				}
			}
			return false;
		}

		inline static bool isIntParam(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_INT){
					return true;
				}
			}
			return false;
		}

		inline static bool isFloatParam(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_FLOAT){
					return true;
				}
			}
			return false;
		}

		inline static bool isStringParam(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_STRING){
					return true;
				}
			}
			return false;
		}

		inline static bool isObjectTypeParam(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_OBJECT_TYPE){
					return true;
				}
			}
			return false;
		}

		inline static bool isGameObjectType(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_OBJECT_TYPE){
					if(param->getObjectType()==OBJECT_TYPE_GAME_OBJECT){
						return true;
					}
				}
			}
			return false;
		}

		inline static bool isComponentType(GDataParam* param)
		{
			if(param!=0){
				if(param->getParamType()==GTYPE_OBJECT_TYPE){
					if(Object::isComponent(param->getObjectType())){
						return true;
					}
				}
			}
			return false;
		}
		GDataType getParamType();
		int getByteCount();
		char* getData();
		
		bool getBool();
		int getInt();
		float getFloat();
		std::string getString();
		ObjectType getObjectType();
		
	};

	typedef std::vector<GDataParam*> GDataParamList;

	class GDataParser
	{
	private:
		GDataName _name;
		std::vector<GDataType> paramTypeList;
		std::vector<int> paramByteCountList;
		std::vector<GDataParam*> _paramList;
		int _paramCount;
		int _index;//read index
		GDatagram *_datagram;
		bool _success;//is parse success
	public:
		GDataName getName();
		GDataParam* getParam(int index);
		GDataParam* getParam();
		GDataParser(GDatagram* datagram);
		GDataParser(std::string fileName);
		~GDataParser();

		void parse();

		inline bool success()
		{
			return _success;
		}
	};

	class GDataGenerator
	{
	public:
		
	private:
		GDataName _name;
		std::vector<GDataParam*> _paramList;
		int _paramCount;

		int _length;
		GDatagram *_datagram;
	public:
		~GDataGenerator(void);

		GDataGenerator(GDataName name);
		void addBoolParam(bool b);
		void addIntParam(int i);
		void addFloatParam(float f);
		void addDoubleParam(double d);
		void addStringParam(std::string str);
		void addBytesParam(char *bytes,int count);
		void addObjectTypeParam(ObjectType type);

		GDatagram* genDatagram();

		void serialize(std::string fileName);
	};
}
#endif
